//
// Created by 33145 on 2023/1/6.
//
#include "../sylar/log.h"
#include "../sylar/config.h"
#include <iostream>
#include <vector>
#include "yaml-cpp/yaml.h"

#if 0
//sylar::ConfigVar<int>::ptr g_int_value_config = sylar::Config::LookUp("system.port", (int)8080, "system port");
//sylar::ConfigVar<float>::ptr g_float_value_config = sylar::Config::LookUp("system.value", (float)10.2f, "system value");
sylar::ConfigVar<std::vector<int>>::ptr g_int_vec_value_config = sylar::Config::LookUp("system.int_vec", std::vector<int>(1, 2), "system int value");
sylar::ConfigVar<std::list<int>>::ptr g_int_list_value_config = sylar::Config::LookUp("system.int_list", std::list<int>(1, 2), "system list value");
sylar::ConfigVar<std::set<int>>::ptr g_int_set_value_config = sylar::Config::LookUp("system.int_set", std::set<int>{1, 2}, "system list value");
sylar::ConfigVar<std::unordered_set<int>>::ptr g_int_unordered_set_value_config = sylar::Config::LookUp("system.int_unordered_set", std::unordered_set<int>{5, 6}, "system unordered_set value");
sylar::ConfigVar<std::map<std::string, int>>::ptr g_int_map_value_config = sylar::Config::LookUp("system.int_map", std::map<std::string, int>{{"hello", 5}, {"world", 6}}, "system string int value");
sylar::ConfigVar<std::unordered_map<std::string, int>>::ptr g_int_unordered_map_value_config = sylar::Config::LookUp("system.int_unordered_map", std::unordered_map<std::string, int>{{"hello", 5}, {"world", 6}}, "system unordered string int value");

void print_yaml(const YAML::Node& node, int level) {

  if (node.IsScalar()) {  // 如果当前判断的node是个纯量
    SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << std::string(level * 4, ' ')
                                     << node.Scalar() << " - " <<node.Type() << " - " << level;
  } else if (node.IsNull()) {  // 如果啥也没有
    SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << std::string(level * 4, ' ')
                                     << "NULL - " <<node.Type() << " - " << level;
  } else if (node.IsMap()) {  // 如果是字典(键值对，由冒号表示)
    for (auto it = node.begin(); it != node.end(); ++it) {  // 遍历字典，形成递归输出
      SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << std::string(level * 4, ' ') << it->first << "x - "
                                       << it->second.Type() << " - " << level;
      print_yaml(it->second, level + 1);
    }
  } else if (node.IsSequence()) {  // 如果是数组(由‘-’表示)
    for (size_t i = 0; i < node.size(); ++i) {
      SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << std::string(level * 4, ' ')
                                       << i  << " - " << node[i].Type() << " - " << level;
      print_yaml(node[i], level + 1);
    }
  }
}

void test_yaml() {
  // 用LodeFile打开yml文件
  YAML::Node root = YAML::LoadFile("/home/orange/workspace/bin/config/test.yml");
  print_yaml(root, 0);
  // SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << '\n' << root;
}

void test_config() {
  // SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << " before: " << g_int_value_config->getValue();
  // SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << " before: " << g_float_value_config->toString();
  // std::cout << "test config" << std::endl;
#define XX(g_var, name, prefix) \
  { \
    auto& v = g_var->getValue(); \
    for (auto& i : v) { \
      SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << #prefix "  "  #name ": "<< i; \
    }  \
    SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << #prefix "  "  #name " yaml: "<< g_var->toString();                              \
  }

#define XX_M(g_var, name, prefix) \
  { \
    auto& v = g_var->getValue(); \
    for (auto& i : v) { \
      SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << #prefix "  "  #name ": {" \
                      << i.first << "  " << i.second << " }"; \
    }  \
    SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << #prefix "  "  #name " yaml: "<< g_var->toString();                              \
  }

  XX(g_int_vec_value_config, int_vec, before);
  XX(g_int_list_value_config, int_list, before);
  XX(g_int_set_value_config, int_set, before);
  XX(g_int_unordered_set_value_config, int_unordered_set, before);
  XX_M(g_int_map_value_config, int_map, before);
  XX_M(g_int_unordered_map_value_config, int_unordered_map, before);

  YAML::Node root = YAML::LoadFile("/home/orange/workspace/bin/config/test.yml");
  sylar::Config::LoadFromYaml(root);

  // SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << " after: " << g_int_value_config->getValue();
  // SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << " after: " << g_float_value_config->toString();

  XX(g_int_vec_value_config, int_vec, after);
  XX(g_int_list_value_config, int_list, after);
  XX(g_int_set_value_config, int_set, after);
  XX(g_int_unordered_set_value_config, int_unordered_set, after);
  XX_M(g_int_map_value_config, int_map, after);
  XX_M(g_int_unordered_map_value_config, int_unordered_map, after);
}
#endif

class Person {
public:
  Person() {}
  std::string m_name = "";
  int m_age = 0;
  bool m_sex = 0;

  bool operator==(const Person& oth) const {
    return m_name == oth.m_name && m_age == oth.m_age && m_sex == oth.m_sex;
  }
  std::string toString() const {
    std::stringstream ss;
    ss << "{ Person name = " << m_name
       << " age = " << m_age
       << " sex = " << m_sex
       << " }";
    return ss.str();
  }
};

namespace sylar {

template <>
class LexicalCast<std::string, Person> {
public:
  Person operator() (const std::string& v) {
    // 把一段字符串转化为Node类型的数据（即？）
    YAML::Node node = YAML::Load(v);
    Person p;
    p.m_name = node["name"].as<std::string>();
    p.m_age = node["age"].as<int>();
    p.m_sex = node["sex"].as<bool>();
    // std::cout << "string to set" << std::endl;
    return p;
  }
};
template <>
class LexicalCast<Person, std::string> {
public:
  std::string operator() (const Person& p) {
    YAML::Node node;
    node["name"] = p.m_name;
    node["age"] = p.m_age;
    node["sex"] = p.m_sex;
    // std::cout << "set to string" << std::endl;
    std::stringstream ss;
    ss << node;
    return ss.str();
  }
};
}

sylar::ConfigVar<Person>::ptr g_person = sylar::Config::LookUp("class.person", Person(), "system person");
sylar::ConfigVar<std::map<std::string, Person>>::ptr g_person_map = sylar::Config::LookUp("class.map", std::map<std::string, Person>(), "system person map");
sylar::ConfigVar<std::map<std::string, std::vector<Person>>>::ptr g_person_vec_map = sylar::Config::LookUp("class.vec_map", std::map<std::string, std::vector<Person>>(), "system person map");


void test_class() {
  // SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << " before " << g_person->getValue().toString() << " - " << g_person->toString();

#define XX_PM(g_var, prefix) \
  {                           \
    auto m = g_person_map->getValue(); \
    for (auto& i : m) { \
      SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << #prefix << "  " << i.first << "  " << i.second.toString(); \
    }                        \
    SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << #prefix << "  " << "size = " << m.size(); \
  }

  g_person->addListener([](const Person& old_value, const Person& new_value) {
    SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << "\n old value = " << old_value.toString()
                  << " \nnew value " << new_value.toString();
  });

  XX_PM(g_person_map, "class.map before");

  YAML::Node root = YAML::LoadFile("/home/orange/workspace/bin/config/test.yml");
  sylar::Config::LoadFromYaml(root);

  // SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << " after " << g_person->getValue().toString() << " - " << g_person->toString();

  XX_PM(g_person_map, "class.map after");
}

void test_log() {
  static sylar::Logger::ptr system_log = SYLAR_LOG_NAME("system");
  SYLAR_LOG_INFO(system_log) << "hello system" << std::endl;
  // 调用 LogManager 的 toYamlString
  // std::cout << sylar::LoggerMgr::GetInstance()->toYamlString() << std::endl;
  YAML::Node root = YAML::LoadFile("/home/orange/workspace/bin/config/test.yml");
  sylar::Config::LoadFromYaml(root);
  std::cout << "---------------------" << std::endl;
  // std::cout << sylar::LoggerMgr::GetInstance()->toYamlString() << std::endl;
  // std::cout << "---------------------" << std::endl;
  // std::cout << SYLAR_LOG_NAME("root")->toYamlString() << std::endl;

  // SYLAR_LOG_INFO(system_log) << "hello system" << std::endl;
  system_log->setFormatter("%d%T%m%n");
  // SYLAR_LOG_INFO(system_log) << "hello system" << std::endl;
}

int main(int argc, char** argv) {
  // std::cout << "hello wrold" << std::endl;
  // test_yaml();
  // test_config();
  test_class();
  test_log();
  return 0;
}